这篇内容是在有道云旧笔记基础上重新整理的 技术实践 笔记。原始记录偏碎片化,这里补充了使用场景、阅读顺序和落地时需要注意的边界,方便以后在项目里快速复用。
适用场景 前端业务中需要快速处理数据、DOM、浏览器能力或通用工具函数时参考。 把散落在项目里的小技巧抽成可复用代码片段,减少重复实现。 排查兼容性和边界输入问题前,先用本文示例确认核心思路。 核心要点 正文已经按 「1. 数据库设计」、「1.1 user 表」、「1.2 role 表」、「1.3 permission 表」 等小节组织,阅读时可以先定位到当前问题对应的小节。 保留了 28 段可直接参考的代码或命令,主要涉及 sql、typescript,复制前需要按当前项目路径、版本和变量名做调整。 好的,我将根据你之前提出的需求整理出一个完整的权限管理示例,包含用户、角色、权限的管理,并支持用户的个性化权限设置(增加或撤销某个权限)。以下是完整的示例:
1. 数据库设计 我们首先设计 5 个表来管理用户、角色、权限以及个性化权限。
1.1 user 表 存储用户信息。
1 2 3 4 5 6 CREATE TABLE user ( id SERIAL PRIMARY KEY, -- 自增主键 username VARCHAR (255 ) NOT NULL UNIQUE, -- 用户名(唯一) password VARCHAR (255 ) NOT NULL -- 密码(加密存储) );
1.2 role 表 存储角色信息。
1 2 3 4 5 CREATE TABLE role ( id SERIAL PRIMARY KEY, -- 自增主键 name VARCHAR (255 ) NOT NULL UNIQUE -- 角色名称(唯一) );
1.3 permission 表 存储权限信息。
1 2 3 4 5 6 CREATE TABLE permission ( id SERIAL PRIMARY KEY, -- 自增主键 name VARCHAR (255 ) NOT NULL UNIQUE, -- 权限名称 description TEXT -- 权限描述 );
1.4 user_roles 表 存储用户与角色的多对多关系。
1 2 3 4 5 6 CREATE TABLE user_roles ( userId INT REFERENCES user (id) ON DELETE CASCADE, roleId INT REFERENCES role (id) ON DELETE CASCADE, PRIMARY KEY (userId, roleId) );
1.5 role_permissions 表 存储角色与权限的多对多关系。
1 2 3 4 5 6 CREATE TABLE role_permissions ( roleId INT REFERENCES role (id) ON DELETE CASCADE, permissionId INT REFERENCES permission (id) ON DELETE CASCADE, PRIMARY KEY (roleId, permissionId) );
1.6 user_permissions 表 存储用户额外分配的权限。
1 2 3 4 5 6 CREATE TABLE user_permissions ( userId INT REFERENCES user (id) ON DELETE CASCADE, permissionId INT REFERENCES permission (id) ON DELETE CASCADE, PRIMARY KEY (userId, permissionId) );
1.7 user_permissions_revoke 表 存储用户被剥夺的权限。
1 2 3 4 5 6 CREATE TABLE user_permissions_revoke ( userId INT REFERENCES user (id) ON DELETE CASCADE, permissionId INT REFERENCES permission (id) ON DELETE CASCADE, PRIMARY KEY (userId, permissionId) );
2. 实体类设计 使用 TypeORM 来定义实体类,分别映射到上述的数据库表。
2.1 User 实体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm' ;import { Role } from './role.entity' ;import { Permission } from './permission.entity' ;@Entity () export class User { @PrimaryGeneratedColumn () id: number; @Column ({ unique: true }) username: string; @Column () password: string; @ManyToMany (() => Role) @JoinTable ({ name: 'user_roles' , joinColumn: { name: 'userId' }, inverseJoinColumn: { name: 'roleId' }, }) roles: Role[]; @ManyToMany (() => Permission) @JoinTable ({ name: 'user_permissions' , joinColumn: { name: 'userId' }, inverseJoinColumn: { name: 'permissionId' }, }) extraPermissions: Permission[]; @ManyToMany (() => Permission) @JoinTable ({ name: 'user_permissions_revoke' , joinColumn: { name: 'userId' }, inverseJoinColumn: { name: 'permissionId' }, }) revokedPermissions: Permission[]; }
2.2 Role 实体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from 'typeorm' ;import { Permission } from './permission.entity' ;import { User } from './user.entity' ;@Entity () export class Role { @PrimaryGeneratedColumn () id: number; @Column ({ unique: true }) name: string; @ManyToMany (() => Permission) @JoinTable ({ name: 'role_permissions' , joinColumn: { name: 'roleId' }, inverseJoinColumn: { name: 'permissionId' }, }) permissions: Permission[]; @ManyToMany (() => User, user => user.roles) users: User[]; }
2.3 Permission 实体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm' ;@Entity () export class Permission { @PrimaryGeneratedColumn () id: number; @Column ({ unique: true }) name: string; @Column () description: string; }
3. 服务逻辑 为了获取用户的有效权限,我们需要从数据库中获取角色权限、用户的额外权限和撤销的权限,并进行合并。
3.1 获取用户的有效权限 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import { Injectable } from '@nestjs/common' ;import { InjectRepository } from '@nestjs/typeorm' ;import { Repository } from 'typeorm' ;import { User } from './user.entity' ;@Injectable () export class UserService { constructor ( @InjectRepository (User) private userRepository: Repository<User>, ) {} async findOneById (userId: number): Promise <User> { return this .userRepository.findOne ({ where: { id: userId }, relations: ['roles' , 'roles.permissions' , 'extraPermissions' , 'revokedPermissions' ], }); } async getUserEffectivePermissions (userId: number): Promise <string[]> { const user = await this .findOneById (userId); if (!user) { throw new Error ('User not found' ); } const rolePermissions = user.roles.flatMap (role => role.permissions); const extraPermissions = user.extraPermissions; const revokedPermissions = user.revokedPermissions; const effectivePermissions = [ ...rolePermissions, ...extraPermissions, ].filter (permission => !revokedPermissions.some (revoked => revoked.id === permission.id)); return [...new Set (effectivePermissions.map (permission => permission.name))]; } }
4. 权限守卫 为了在控制器中检查权限,我们可以使用 PermissionsGuard 来判断用户是否有执行某操作的权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common' ;import { Reflector } from '@nestjs/core' ;import { UserService } from './user.service' ;@Injectable () export class PermissionsGuard implements CanActivate { constructor ( private reflector: Reflector, private userService: UserService, ) {} async canActivate (context: ExecutionContext): Promise <boolean> { const requiredPermissions = this .reflector.get <string[]>('permissions' , context.getHandler ()); if (!requiredPermissions) { return true ; } const request = context.switchToHttp ().getRequest (); const user = request.user; const userPermissions = await this .userService.getUserEffectivePermissions (user.id); return requiredPermissions.every (permission => userPermissions.includes (permission)); } }
5. 示例数据 用户 bob 是 editor 角色,有 read_resource 和 edit_resource 权限。
给 bob 额外分配 delete_resource 权限。
撤销 bob 的 edit_resource 权限。
user_permissions 表 1 2 3 4 5 6 +--------+-------------+ | userId | permissionId | +--------+-------------+ | 2 | 3 | -- bob 额外获得 delete_resource 权限 +--------+-------------+
user_permissions_revoke 表 1 2 3 4 5 6 +--------+-------------+ | userId | permissionId | +--------+-------------+ | 2 | 2 | -- bob 被撤销了 edit_resource 权限 +--------+-------------+
6. 总结 这个示例展示了如何在 NestJS 和 TypeORM 中设计用户、角色、权限管理系统,支持用户个性化的权限增补和撤销。
以下是一些常见网站的用户角色及其中文和英文名称:
1. 管理员 (Admin) 2. 超级管理员 (Super Admin) 3. 编辑 (Editor) 4. 作者 (Author) 5. 审核员 (Reviewer) 6. 会员 (Member) 7. 访客 (Guest) 8. 支持人员 (Support Staff) 9. 操作员 (Operator) 10. 审计员 (Auditor) 这些角色可以根据具体网站的需求进行调整和扩展。例如,电子商务网站可能还会有采购员 (Purchaser) 、卖家 (Seller) 等角色。
实践检查清单 先确认当前工具链版本和运行环境,再决定是否直接复用示例。 把验证过的最终命令、配置或代码补回本文,减少下次重复排查。 涉及接口、服务端或权限逻辑时,补充失败分支和权限边界测试。 复盘小结 这篇笔记更适合作为问题排查或方案落地前的速查材料。后续如果在真实项目中再次遇到同类问题,可以继续把具体版本、报错信息、最终取舍和验证结果补到对应小节里,让它从代码片段逐步沉淀成完整方案。
Author: 蓝思同学
Permalink: https://www.lancema.com/posts/2023/study/NestJS 用户权限.html
Slogan: small is beautiful, small is powerful !